/*
 A class to hold a canvas point that can (optionally) be dragged.
 
 Requirements:
	- The canvas.js script file.
*/

const CANVAS_PIN_INSTEAD_OF_SQUARE = true;

// the displayed size of the point, in pixels.
const POINT_SIZE = CANVAS_PIN_INSTEAD_OF_SQUARE ? 12 : 8;

// the clickable region of the point, in pixels.
const CLICKABLE_POINT_SIZE = 14;

// the snap radius of the point, in pixels.
const SNAP_RADIUS_2D = 10;

// a simple class to hold two points.
function Point2D(u, v, movable) {
	this.u = u;
	this.v = v;
	this.snapped = false;
	this.movable = movable;
	this.dragged = false;
	this.movedPoint = false;
}

Point2D.prototype.setStyle = function(fillStyle, snappedStroke, unsnappedStroke, lineWidth) {
	this.fillStyle       = fillStyle;
	this.snappedStroke   = snappedStroke;
	this.unsnappedStroke = unsnappedStroke;
	this.lineWidth       = lineWidth;
}

// draw the point.
Point2D.prototype.draw = function() {
	var ctx = getContext()

	ctx.fillStyle = this.fillStyle;
	if ( this.snapped ) {
		ctx.strokeStyle = this.snappedStroke;
	} else {
		ctx.strokeStyle = this.unsnappedStroke;
	}
	ctx.lineWidth = this.lineWidth;
	
	if ( CANVAS_PIN_INSTEAD_OF_SQUARE ) {
		var curU = this.u
		var curV = this.v;

		ctx.beginPath();
		ctx.moveTo(curU, curV);
		curU -= 0.5*POINT_SIZE;
		curV -= 0.75*POINT_SIZE;
		ctx.lineTo(curU, curV);
		curV -= 0.75*POINT_SIZE;
		ctx.lineTo(curU, curV);
		curU += POINT_SIZE;
		ctx.lineTo(curU, curV);
		curV += 0.75*POINT_SIZE;
		ctx.lineTo(curU, curV);
		curU = this.u;
		curV = this.v;
		ctx.lineTo(curU, curV);
		ctx.closePath();

		ctx.fill();
		ctx.stroke();
	} else {
		ctx.fillRect(this.u-POINT_SIZE / 2, this.v-POINT_SIZE / 2, POINT_SIZE, POINT_SIZE);
		ctx.strokeRect(this.u-POINT_SIZE / 2, this.v-POINT_SIZE / 2, POINT_SIZE, POINT_SIZE);
	}
}

// returns true if (x,y) is over the point.
Point2D.prototype.onXY = function(x, y) {
	var isOnXY;

	if ( CANVAS_PIN_INSTEAD_OF_SQUARE ) {
		isOnXY = (this.u - CLICKABLE_POINT_SIZE / 2 < x && x < this.u + CLICKABLE_POINT_SIZE / 2 ) &&
		   		 (this.v - CLICKABLE_POINT_SIZE * 1.5 < y && y < this.v + CLICKABLE_POINT_SIZE * 1.5 );
	} else {
		isOnXY = (this.u - CLICKABLE_POINT_SIZE / 2 < x && x < this.u + CLICKABLE_POINT_SIZE / 2 ) &&
		   		 (this.v - CLICKABLE_POINT_SIZE / 2 < y && y < this.v + CLICKABLE_POINT_SIZE / 2 );
	}

	return isOnXY;
}

// moves the point, if the point can be moved.
Point2D.prototype.setPosition = function(x, y) {
	if ( this.movable ) {
		this.u = x;
		this.v = y;
		this.movedPoint = true;
	}
}

// set if the point is currently being dragged.
Point2D.prototype.setDragged = function(dragged) {
	this.dragged = dragged;
}

// set if the point is currently snapped.
Point2D.prototype.setSnapped = function(snapped) {
	this.snapped = snapped;
}

// snaps this point to the closest other point, if any of them
// fall in the snap radius.
Point2D.prototype.snapPoint = function(x, y, otherPoints) {
	var closestRadius = -1;
	var closestPoint = null;

	// find the closest point to the mouse.
	for ( var i in otherPoints ) {
		var point = otherPoints[i];
		var radius = l2distance(x, y, point.u, point.v);
		if ( closestRadius == -1 || radius < closestRadius ) {
			closestRadius = radius;
			closestPoint = point;
		}
	}
	if ( closestRadius != -1 && closestRadius < SNAP_RADIUS_2D ) {
		// snap to this point.
		this.setPosition(closestPoint.u, closestPoint.v);
		this.snapped = true;
	} else {
		this.setPosition(x,y);
		this.snapped = false;
	}
}
